package display;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import structs.adoption.Adoption;
import structs.book.Book;
import structs.database.Database;
import structs.quantity.Quantity;
import structs.quantity.QuantityList;
import structs.term.Term;
import structs.term.dept.Department;
import structs.term.dept.Department.Code;


public class InventoryData {
	
	private Map<String,Book> booksISBN, booksInvNum;
	private Map<String,QuantityList> quantities;
	private Term curTerm;
	private Database database;
	private ArrayList<Term> terms;
	
	private ReentrantReadWriteLock bookLock = new ReentrantReadWriteLock(),
								   qtyLock = new ReentrantReadWriteLock(),
								   adptLock = new ReentrantReadWriteLock();
	
	/*public InventoryData(Database db) {
		database = db;
	}*/
	
	public void setDB(Database db) { database = db; }
	
	public QuantityList qtyLookup(String isbn) {
		qtyLock.readLock().lock();
		QuantityList out = quantities.get(isbn);
		qtyLock.readLock().unlock();
		
		return out;
	}
	
	public Book addBook(Book b) {
	
		bookLock.writeLock().lock();
		booksISBN.put(String.valueOf(b.getISBN()),b);
		booksInvNum.put(b.getInv_num().toLowerCase(), b);
		bookLock.writeLock().unlock();
		return b;
		
	}
	public Quantity addQuantity(String isbn, Quantity q) {
		qtyLock.writeLock().lock();
		QuantityList ql = quantities.get(isbn);
		
		if (ql == null) {
			ql = new QuantityList();
			quantities.put(isbn, ql);
		}
		ql.addQuantity(q);
		qtyLock.writeLock().unlock();
		return q;
		
	}
	
	public boolean containsBook(String isbn) {
		bookLock.readLock().lock();
		boolean out = booksISBN.containsKey(isbn);
		bookLock.readLock().unlock();
		return out;
	}
	
	public Book getBook(String inv_num) {
		Book out = null;
		
		bookLock.readLock().lock();
		
		if (inv_num.length() == 7)
			out = booksInvNum.get(inv_num.toLowerCase());
		else
			out = booksISBN.get(Util.Util.isbn13(inv_num));
		
		bookLock.readLock().unlock();

		if (out == null)
			try {
				out = database.getBook(inv_num);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		return out;
	}
	
	public Adoption addAdoption(Adoption a) {
		adptLock.writeLock().lock();
		curTerm.addAdoption(a);
		adptLock.writeLock().unlock();
		
		return a;
	}
	
	public Adoption[] getAdoptions() {
		adptLock.readLock().lock();
		Adoption[] out = (Adoption[])curTerm.getAdoptionArray();
		adptLock.readLock().unlock();
		
		return out;
	}
	
	public ArrayList<Term> getTerms() {
		Collections.sort(terms);
		return terms;
	}
	
	public Term getCurTerm() {return curTerm;}
	
	public void selectTerm(Term t) {
		curTerm = database.getTerm(t);
		
		if (!terms.contains(curTerm)) {
			terms.add(curTerm);
		}

		booksISBN = curTerm.getBooksISBN();
		booksInvNum = curTerm.getBooksInvNum();
		
		// get quantities
		quantities = database.getQtys();
		// get adoptions
		//adoptions = getAdpts();	
	}
	
	public void createTerm() {
		
		NewTermDialog ntd = new NewTermDialog(this,database);
		ntd.setVisible(true);
		ntd.setAlwaysOnTop(true);
		//TODO: make it so you can't click around this window.
	}
	
	public void termRollover(){}
	
	public void importData(){}
	
	public static int count = 0;
	
	public Object[] initTerms() {
		if (terms != null)
			return terms.toArray();
		
		terms = database.getTerms();
		Object[] out;
		if (terms.size() > 0) {
			selectTerm(terms.get(0));
			out = terms.toArray();
		}
		else
			out = new Object[]{};
		return out;
	}
	
	public void save(){
		for (Term t : terms)
		database.saveTerm(t);
	}

	/**
	 * @param id
	 * @return
	 * @see structs.term.Term#getDept(structs.term.dept.Department.Code)
	 */
	public Department getDept(Code id) {
		return curTerm.getDept(id);
	}

	/**
	 * @return
	 * @see structs.term.Term#getDepts()
	 */
	public Collection<Department> getDepts() {
		return curTerm.getDepts();
	}
	
	public Collection<Department> getDeptsOrdered() {
		ArrayList<Department> out = new ArrayList<Department>(getDepts());
		Collections.sort(out);
		return out;
	}
}
